from Being import *
from random import randrange
from time import time
from math import sqrt

'''````````````````````````````````````````````````````````````````````````````````````````````````````````````````````
` Zombie class, extends Being. Responsible for moving zombie and triggering the conversion between humans and zombies `
````````````````````````````````````````````````````````````````````````````````````````````````````````````````````'''

class Zombie(Being):

	color = "#0f0"
	speed = 1
	sight_dist = 30
	
	def move(self):
		if self.x >= 600 or self.x <= 0 or self.y >= 400 or self.y <= 0:
			
			#store the previous x and y
			oldx = self.x
			oldy = self.y
			
			#if this being is off of the screen, put them back
			if self.x >= 599:
				self.x = 598
			elif self.x <= 1:
				self.x = 2
			if self.y >= 399:
				self.y = 398
			elif self.y <= 1:
				self.y = 2
			self.canvas.move(self.rectangle, self.x-oldx, self.y-oldy)
		
		# set the current nearest human to some ridiculous number - this will never be the closest human, 
		# but it allows us to maintain constant logic (always look for the lowest, as opposed to having a different first-state
		human_distance = 1000;
		
		#also say that we are not chasing at the moment
		chasing = False
		
		#if this zombie knows the player...
		if hasattr(self,"player"):
			
			#... and the player is not a zombie...
			if not self.player.zombified:
				
				#... then figure out how far the player is from this zombie
				this_distance = sqrt(((self.x-self.player.x)**2)+((self.y-self.player.y)**2))
				
				#if this player is the closest being and this zombie can see it
				if this_distance < human_distance and this_distance <= self.sight_dist:
					
					#then go into chasing mode, targetting the player
					self.speed = 2
					human_distance = this_distance
					
					if self.x > self.player.x:
						move_x = -self.speed
					else:
						move_x = self.speed
					if self.y > self.player.y:
						move_y = -self.speed
					else:
						move_y = self.speed
					if human_distance < 3:
						#the zombie has 'tagged' the the player, so decrease the their health
						self.player.health -= 1
						
					#this zombie is totally chasing something
					chasing = True
		
		#for the sake of making this more of a *game*, we will make the zombies choose the player as their priority
		#if they are not chasing the player, however, then check to see where the nearest human is
		if hasattr(self,"humans") and not chasing:
			
			for human in self.humans:
				
				#we only want humans that are not zombified - there is a reference to all zombified humans on the canvas for
				#a single iteration of the main loop, so in order to keep zombies from chasing humans undergoing transformation,
				#we include a bit of redundancy
				if not human.is_zombie():
					
					#determine the distance from this zombie to the current human
					this_distance = sqrt(((self.x-human.get_x())**2)+((self.y-human.get_y())**2))
					
					if this_distance < human_distance and this_distance <= self.sight_dist:
						
						#the human is within our sight, so go slightly faster
						self.speed = 2
						human_distance = this_distance
						
						if self.x > human.get_x():
							move_x = -self.speed
						else:
							move_x = self.speed
						if self.y > human.get_y():
							move_y = -self.speed
						else:
							move_y = self.speed
						if human_distance < 2:
							#reset this zombie's hunger timer
							self.last_time = time()
							
							#make a new zombie...
							new_zom = Zombie(self.root,self.canvas,self.buildings)
							new_zom.set_position(human.get_x(),human.get_y())
							new_zom.know_beings(self.humans,self.zombies,self.player)
							self.zombies.append(new_zom)
							
							#and remove the human
							human.canvas.delete(human.rectangle)
							human.zombified = True
							self.humans.remove(human)
							del human
							
							#we just caught a human, so we can't eat another this iteration
							break
							
						chasing = True
					
					#also notify the human if we are within their sight
					if this_distance < human.sight_dist:
						
						if human.chased_by!=0:
							
							#if the human is already chased, determine how far that zombie is from this human
							that_distance = sqrt(((human.chased_by.x-human.get_x())**2)+((human.chased_by.y-human.get_y())**2))
						
						else:
							
							#otherwise, set a ridiculous distance so that when comparing, this zombie will be the closest
							that_distance = 1000
						
						if this_distance<that_distance:
						
							#this zombie is the closest, so tell the human to panic and flee
							human.panicked = True
							human.color = "red"
							human.canvas.delete(human.rectangle)
							human.speed = 3
							human.rectangle = human.canvas.create_rectangle(human.x,human.y,human.x,human.y,fill=human.color,outline='')
							human.chased_by = self
					else:
					
						#else, if the human was previously chased by this zombie and can no longer see it, remove the reference
						if human.chased_by == self:
							human.chased_by = 0
							
		#if the zombie is not currently chasing a human...
		if not chasing:
			
			#make a random movement within this zombie's speed
			self.speed = 1
			move_x = randint(-self.speed,self.speed)
			move_y = randint(-self.speed,self.speed)
			
		#assume there is a collision so that we will enter the hit-test loop at least once
		collision = True
		
		while(collision):
			
			#not set the collision variable to false, so that if there is no collision, we can escape the loop
			collision = False
			
			for building in self.buildings:
				if building.hit_test(self.x+move_x,self.y+move_y):
					collision = True
					
					#we just hit a building, so move again
					move_x = randint(-self.speed,self.speed)
					move_y = randint(-self.speed,self.speed)
					break
			
			if(not collision):
				#no collision, so break!
				break
			
		#assign our new position
		self.x = self.x + move_x
		self.y = self.y + move_y
		
		#and actually move the rectangle
		self.canvas.move(self.rectangle, move_x, move_y)
		
		#if this zombie has been around for 30 seconds without feeding, kill it
		if (time()-self.last_time)>=30:
			self.canvas.delete(self.rectangle)
			if hasattr(self,"zombies"):
				self.zombies.remove(self)